"""
任务模型定义
包含任务和任务执行记录相关模型
"""
import json
from datetime import datetime
from . import db
from .enums import TaskStatus, TaskType
from ..timezone_utils import now as timezone_now

class Task(db.Model):
    """任务模型"""
    __tablename__ = 'tasks'
    
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(200), nullable=False, index=True)
    description = db.Column(db.Text)
    task_type = db.Column(db.Enum(TaskType), nullable=False, default=TaskType.PYTHON_SCRIPT)
    cron_expression = db.Column(db.String(100), nullable=False)
    script_file_path = db.Column(db.String(500), nullable=True)  # 脚本文件路径，当使用用户脚本时可为空
    working_directory = db.Column(db.String(500))
    environment_variables = db.Column(db.Text)  # JSON格式存储
    dependencies = db.Column(db.Text)  # JSON格式存储依赖包
    timeout = db.Column(db.Integer, default=0)  # 超时时间(秒)，0表示无超时限制
    retry_attempts = db.Column(db.Integer, default=0)  # 重试次数
    status = db.Column(db.Enum(TaskStatus, values_callable=lambda x: [e.value for e in x]), default=TaskStatus.PENDING, nullable=False)
    is_enabled = db.Column(db.Boolean, default=True, nullable=False)
    
    # 通知配置
    notify_on_failure = db.Column(db.Boolean, default=False, nullable=False)  # 失败时是否通知
    notification_config_id = db.Column(db.Integer, db.ForeignKey('notification_configs.id'), nullable=True, index=True)  # 关联通知配置
    
    # 外键
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, index=True)
    user_script_id = db.Column(db.Integer, db.ForeignKey('user_scripts.id'), nullable=True, index=True)  # 关联用户脚本
    
    # 时间戳
    created_at = db.Column(db.DateTime, default=timezone_now, nullable=False)
    updated_at = db.Column(db.DateTime, default=timezone_now, onupdate=timezone_now)
    last_run_at = db.Column(db.DateTime)  # 最后执行结束时间
    last_started_at = db.Column(db.DateTime)  # 最后开始执行时间
    
    # 关联执行记录
    executions = db.relationship('TaskExecution', backref='task', lazy='dynamic', 
                                cascade='all, delete-orphan', order_by='TaskExecution.started_at.desc()')
    
    # 关联用户脚本
    user_script = db.relationship('UserScript', backref='tasks')
    
    # 关联通知配置
    notification_config = db.relationship('NotificationConfig', backref='tasks')
    
    def to_dict(self):
        """转换为字典"""
        # 解析环境变量和依赖项
        try:
            env_vars = json.loads(self.environment_variables) if self.environment_variables else {}
        except (json.JSONDecodeError, TypeError):
            env_vars = {}
            
        try:
            dependencies = json.loads(self.dependencies) if self.dependencies else []
        except (json.JSONDecodeError, TypeError):
            dependencies = []
        
        # 获取创建者用户名
        creator_username = None
        if self.creator:
            creator_username = self.creator.username
        
        return {
            'id': self.id,
            'name': self.name,
            'description': self.description,
            'task_type': self.task_type.value,
            'cron_expression': self.cron_expression,
            'script_file_path': self.script_file_path,
            'working_directory': self.working_directory,
            'environment_variables': env_vars,
            'dependencies': dependencies,
            'timeout': self.timeout,
            'retry_attempts': self.retry_attempts,
            'status': self.status.value,
            'is_enabled': self.is_enabled,
            'notify_on_failure': self.notify_on_failure,
            'notification_config_id': self.notification_config_id,
            'user_id': self.user_id,
            'user_script_id': self.user_script_id,
            'creator': creator_username,  # 添加创建者用户名
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'updated_at': self.updated_at.isoformat() if self.updated_at else None,
            'last_run_at': self.last_run_at.isoformat() if self.last_run_at else None,
            'last_started_at': self.last_started_at.isoformat() if self.last_started_at else None
            # next_run_at 字段已移除，将通过 API 实时计算
        }
    
    def __repr__(self):
        return f'<Task {self.name}>'


class TaskExecution(db.Model):
    """任务执行记录模型"""
    __tablename__ = 'task_executions'
    
    id = db.Column(db.Integer, primary_key=True)
    task_id = db.Column(db.Integer, db.ForeignKey('tasks.id'), nullable=False, index=True)
    execution_id = db.Column(db.String(100), unique=True, nullable=False, index=True)  # 唯一执行ID
    status = db.Column(db.Enum(TaskStatus, values_callable=lambda x: [e.value for e in x]), nullable=False, default=TaskStatus.PENDING)
    
    # 执行信息
    started_at = db.Column(db.DateTime, nullable=False, default=timezone_now, index=True)
    completed_at = db.Column(db.DateTime)
    duration = db.Column(db.Float)  # 执行时长(秒)
    
    # 执行结果
    exit_code = db.Column(db.Integer)
    stdout = db.Column(db.Text(collation='utf8mb4_unicode_ci'))
    stderr = db.Column(db.Text(collation='utf8mb4_unicode_ci'))
    error_message = db.Column(db.Text(collation='utf8mb4_unicode_ci'))
    
    # 执行环境信息
    executor_host = db.Column(db.String(200))
    executor_pid = db.Column(db.Integer)
    celery_task_id = db.Column(db.String(100))  # Celery任务ID，用于停止任务
    retry_count = db.Column(db.Integer, default=0)
    
    def to_dict(self):
        """转换为字典"""
        return {
            'id': self.id,
            'task_id': self.task_id,
            'execution_id': self.execution_id,
            'status': self.status.value,
            'started_at': self.started_at.isoformat() if self.started_at else None,
            'completed_at': self.completed_at.isoformat() if self.completed_at else None,
            'duration': self.duration,
            'exit_code': self.exit_code,
            'stdout': self.stdout,
            'stderr': self.stderr,
            'error_message': self.error_message,
            'executor_host': self.executor_host,
            'executor_pid': self.executor_pid,
            'celery_task_id': self.celery_task_id,
            'retry_count': self.retry_count
        }
    
    def __repr__(self):
        return f'<TaskExecution {self.execution_id}>'